home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Scene 96
/
Scene 96 International Edition (Zyklop Software) (Disc 2) (1997).iso
/
misc
/
coding
/
vgacodng
/
part07.txt
< prev
next >
Wrap
Text File
|
1996-12-15
|
13KB
|
332 lines
VGA-Kurs - Part #7
Hallo Leute! Es wird Zeit für 'T.C.P.'s Beginner's Guide To VGA Coding',
Part VII!
In den ersten 6 Teilen haben wir die Grundlagen des VGA Codings besprochen
(allerdings ohne dabei auf die Register der VGA-Karte selbst einzugehen, wer
dazu Informationen braucht, möge sich bitte ein Buch kaufen, ich empfehle
"VGA- und SVGA-Programmierung" von M. Uphoff, Addison Wesley).
Ich werde ab jetzt in den folgenden Teilen dieses Kurses diese Grundlagen als
Wissen vorraussetzen und auf verschiedene Effekte, Tricks oder ähnliches
eingehen.
In diesem Teil will ich mit einem sehr simplen Effekt anfangen, mit dem sich
allerdings sehr schöne Resultate erzielen lassen: Der Shadebob-Effekt.
Die Shadebobs sind meiner Meinung nach zu Unrecht wegen ihrer einfachen
Programmierung in Verruf gekommen, und werden häufig als Lamer-Effekt betitelt.
Ich für meinen Teil habe nichts gegen Shadebobs in Demos, auch wenn sie schon
etwas älter sind. Man kann mit dem Prinzip wirklich sehr viel anfangen, man
sollte es nur nicht übertreiben, wie es manche ältere Demos zeigen, in denen
zum Teil bis zu 5 Minuten lange Shadebob-Parts enthalten sind.
Aber fangen wir jetzt an.
Das Prinzip der Shadebobs ist einfach erklärt. Wenn man sich ein beliebiges
Quadrat auf dem schwarzen Screen sucht, und alle Pixelwerte dieses Quadrates um
eins erhöht, sieht man ein blaues Quadrat, weil in der Standardpalette nach der
Farbe 0 (schwarz) die Farbe blau kommt. Wenn man nun ein anderes, gleichgroßes
Quadrat nimmt, das sich mit dem alten in einem Pixel überlagert, dann ist dieses
auch blau, nur das eine Pixel, an dem sich die beiden überlagern, hat die Farbe
grün, denn sein Farbwert wurde zweimal erhöht.
Falls ihr euch nicht so genau vorstellen könnt, wie das vor sich geht, hilft
euch vielleicht das Listing weiter.
uses crt;
var n1,n2 : byte;
begin
asm mov ax,13h; int 10h end;
for n1 := 0 to 9 do
for n2 := 0 to 9 do mem[$A000:n2*320+n1] := mem[$A000:n2*320+n1] + 1;
for n1 := 9 to 18 do
for n2 := 9 to 18 do mem[$A000:n2*320+n1] := mem[$A000:n2*320+n1] + 1;
readkey;
asm mov ax,3; int 10h end;
end.
Wenn wir jetzt eine Farbpalette setzen, die einen durchgehenden blauen
Farbverlauf enthält, und ständig neue Quadrate an zufälligen Positionen auf den
Bildschirm setzen, hätten wir den ersten Shadebob-Typ: Die Colorcycle-Bobs.
uses crt;
var Pal : array[0..767] of byte;
n1,n2 : byte;
procedure SetPalette;assembler; { Setzt die Palette in Pal }
asm
mov dx,3C8h
xor al,al
out dx,al
mov cx,768
mov dx,3C9h
mov si,offset pal
@Jmp1:
lodsb
out dx,al
loop @Jmp1
end;
procedure BluePal; { Schreibt eine blaue Palette in Pal setzt sie mittels }
var loop : integer; { SetPalette }
begin
for loop := 0 to 31 do begin
pal[loop*3+2] := loop * 2;
pal[(63-loop)*3+2] := loop * 2;
pal[(loop+64)*3+2] := loop * 2;
pal[(127-loop)*3+2] := loop * 2;
pal[(loop+128)*3+2] := loop * 2;
pal[(191-loop)*3+2] := loop * 2;
pal[(loop+192)*3+2] := loop * 2;
pal[(255-loop)*3+2] := loop * 2;
end;
setpalette;
end;
procedure SetBob(x,y:word); { Setzt ein Bob an die Koords X,Y }
var n1,n2 : byte;
begin
for n1 := 0 to 19 do { Hier werden in einem 20x20 Pixel großen Quadrat }
for n2 := 0 to 19 do { alle Pixelwerte um 1 erhöht }
mem[$A000:(n2+y)*320+n1+x] := mem[$A000:(n2+y)*320+n1+x] + 1;
end;
begin
asm mov ax,13h; int 10h end;
BluePal;
randomize;
repeat
SetBob(random(300),random(180)); { Bob an zufällige Position setzen }
until keypressed;
readkey;
asm mov ax,3; int 10h end;
end.
Das obige Listing enthält noch eine Pascal-Version der SetBob-Routine, die
nicht gerade sehr optimiert ist. Wer also gerade zu viel Zeit hat, kann das
Ganze noch ein bißchen optimieren.
In der dritten Zeile der SetBob-Prozedur kann das '+ 1' durch ein '+ random(4)'
ersetzt werden. Dadurch wird der Effekt körniger. Ist Geschmackssache.
So, das Prinzip der Shadebobs dürfte jetzt klar sein.
Als zweite in der Reihe der verschiedenen Shadebob-Typen wären da die Snakebobs.
Bei dieser Art von Bobs werden entweder ein oder mehrere (je mehr desto besser)
Shadebobs gezeichnet und dann z.B. um ein Pixel nach rechts und eins nach unten
bewegt. Das macht man solange, bis der Bob am unteren Rand des Screens angelangt
hat. Man hat jetzt eine Line, die schräg über den Bildschirm verläuft. Nun
ändert man die Bewegungsrichtung, indem man den Inkrementationsparameter
umkehrt, also den Bob jetzt nach oben bewegt. Trifft der Bob nun auf den rechten
Rand des Screens, kehrt man auch die horizontale Bewegungsrichtung um.
Das sieht dann so aus:
uses crt;
var Pal : array[0..767] of byte;
x1,y1,x2,y2 : word; { X- und Y-Koords der beiden Bobs }
incx1,incy1,incx2,incy2 : shortint; { Inkrementationsparameter }
{ Hier die Prozeduren SetBob und SetPalette einfügen }
procedure RainbowPal; { Erstellt eine bunte Palette }
var loop : integer;
begin
for loop := 0 to 31 do begin
pal[loop*3] := loop * 2;
pal[(63-loop)*3] := loop * 2;
pal[(loop+64)*3+1] := loop * 2;
pal[(127-loop)*3+1] := loop * 2;
pal[(loop+128)*3+2] := loop * 2;
pal[(191-loop)*3+2] := loop * 2;
pal[(loop+192)*3] := loop * 2;
pal[(loop+192)*3+1] := loop * 2;
pal[(loop+192)*3+2] := loop * 2;
pal[(255-loop)*3] := loop * 2;
pal[(255-loop)*3+1] := loop * 2;
pal[(255-loop)*3+2] := loop * 2;
end;
setpalette;
end;
begin
asm mov ax,13h; int 10h end;
RainbowPal;
randomize;
x1 := random(280); { Zufällige X- und Y- Positionen für }
y1 := random(160); { beide Bobs }
x2 := random(280);
y2 := random(160);
incx1 := 1; { Bob 1 wird nach rechts und nach unten }
incy1 := 1; { bewegt }
incx2 := -1; { Bob 2 wird nach links und nach unten }
incy2 := 1; { bewegt }
repeat
inc(x1,incx1); { Bob-Positionen verändern }
inc(y1,incy1);
inc(x2,incx2);
inc(y2,incy2);
if (x1 = 299) or (x1 = 0) then incx1 := -incx1; { Überprüfen, ob einer }
if (y1 = 179) or (y1 = 0) then incy1 := -incy1; { der Bobs am Rand des }
if (x2 = 299) or (x2 = 0) then incx2 := -incx2; { Screens ist, und wenn }
if (y2 = 179) or (y2 = 0) then incy2 := -incy2; { ja dann Wert umkehren }
SetBob(x1,y1); { Die beiden Bobs zeichnen }
SetBob(x2,y2);
until keypressed;
readkey;
asm mov ax,3; int 10h end;
end.
Wir kommen nun zu meinen persönlichen Lieblingsbobs, den Sinusbobs.
Der Name basiert darauf, daß hier mittels einer Sinusformel die Koordinaten
für die Bobs berechnet werden, wodurch sehr schöne Formen zustande kommen.
Allerdings sind die Quadratischen Bobs hier nicht geeignet, passender sind
runde. Man kann stattdessen natürlich auch kleine Symbole oder Logos benutzen,
das sieht nicht schlecht aus.
uses crt;
const VGA : word = $A000;
SinOfs = 40; { Offset }
SinAmp = 50; { Amplitude }
SinLen = 255; { und Länge der Sinustabelle }
SprPic : array[0..15,0..15] of byte = (
(0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0),
(0,0,0,0,2,2,3,3,3,3,2,2,0,0,0,0),
(0,0,0,2,3,3,3,3,3,3,3,3,2,0,0,0),
(0,0,2,3,3,3,3,3,3,3,3,3,3,2,0,0),
(0,2,3,3,3,3,3,3,3,3,3,3,3,3,2,0),
(0,2,3,3,3,3,3,3,3,3,3,3,3,3,2,0),
(2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2),
(2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2),
(2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2),
(2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2),
(0,2,3,3,3,3,3,3,3,3,3,3,3,3,2,0),
(0,2,3,3,3,3,3,3,3,3,3,3,3,3,2,0),
(0,0,2,3,3,3,3,3,3,3,3,3,3,2,0,0),
(0,0,0,2,3,3,3,3,3,3,3,3,2,0,0,0),
(0,0,0,0,2,2,3,3,3,3,2,2,0,0,0,0),
(0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0)
);
var SinTab : array[0..SinLen] of word;
Pal : array[0..767] of byte;
X,Y,n : integer;
I1,I2,J1,J2 : byte;
{ Hier die Prozeduren SetPalette und BluePal einsetzen }
procedure CalcSinus(SinPar:byte);
begin
for n := 0 to SinLen do
SinTab[n] := round(sin(n*SinPar*pi/SinLen)*SinAmp)+SinOfs;
end;
procedure WaitRetrace;assembler;
asm
mov dx,3DAh
@loop1:
in al,dx
and al,08h
jz @loop1
@loop2:
in al,dx
and al,08h
jz @loop2
end;
procedure SetBob(X,Y:word;W,H:byte;Sprite:pointer);assembler;
asm
push ds { DS sichern }
lds si,[Sprite] { DS:SI mit dem Spritepointer laden }
mov es,vga { VGA-Segment nach ES }
cld
mov ax,Y { Offset des Bobs berechnen }
shl ax,6
mov di,ax
shl ax,2
add di,ax
add di,X
mov bh,H
mov cx,320
sub cl,W
sbb ch,0
@L:
mov bl,W
@L2:
lodsb { Wert laden }
or al,al { Wert = 0 ? }
jz @S { Wenn ja, nicht erhöhen }
mov dl,es:[di] { Pixelwert vom VGA holen }
add dl,al { Wert erhöhen }
and dl,63
mov es:[di],dl { und neuen Pixelwert schreiben }
@S:
inc di { nächste Pixelposition }
dec bl { Zähler dekrementieren }
jnz @L2 { wenn <> 0 dann innerer Loop }
add di,cx { nächste Zeile auf VGA }
dec bh { Zähler dekrementieren }
jnz @L { wenn <> 0 dann äußerer Loop }
pop ds
end;
begin
asm mov ax,13h; int 10h end;
BluePal;
randomize;
CalcSinus(random(8)); { Sinustabelle berechnen }
I1 := 0; { Indizes für Sinustabelle }
I2 := 200;
J1 := 0;
J2 := 200;
repeat
X := SinTab[I1]+SinTab[I2]; { Werte addieren }
Y := SinTab[J1]+SinTab[J2];
inc(I1,2); { Neue Indexwerte }
inc(I2,3);
inc(J1);
inc(J2,2);
waitretrace;
SetBob(80+X,Y,16,16,addr(SprPic)); { Bob zeichnen }
until keypressed;
readkey;
asm mov ax,3; int 10h end;
end.
Das Wesentliche hier, das Berechnen der Sinustabelle, findet in der Prozedur
CalcSinus statt, der ein Parameter übergeben wird, nach dem sich die spätere
Form der Bobs richtet. Ebenso können die Konstanten für das Offset und die
Amplitude der Tabelle am Anfang des Listings verändert werden. Wer ein bißchen
Ahnung von Mathe hat, kann so zu sehr schönen Formen kommen.
Die Prozedur SetBob ist in diesem Fall 100% Assembler, allerdings zeichnet sie
kein Quadrat, sondern das Sprite SprPic auf den Bildschirm, wobei sie die
Pixelwerte um die Werte im Sprite erhöht.
Ich hoffe, ihr könnt mit diesen schönen Effekten etwas anfangen und aus ihnen
lernen. Es gibt noch eine Menge anderer Möglichkeiten, die einem die Shadebobs
bieten. Man könnte sie zum Beispiel mit ein paar Vektorroutinen verbinden.
Auch Delay-Vektoren wären hiermit möglich, allerdings ist es wohl sinnvoller,
wenn man, anstatt alle Farbwerte des vorigen Objekts herabzusetzen, das Objekt
neu in einer dunkleren Farbe zeichnet.
In der nächsten Ausgabe werde ich wahrscheinlich einen anderen Effekt
beschreiben. Welchen, weiß ich noch nicht genau.
[ This text copyright (c) 1995-96 Johannes Spohr. All rights reserved. ]
[ Distributed exclusively through PC-Heimwerker, Verlag Thomas Eberle. ]
[ ]
[ No part of this document may be reproduced, transmitted, ]
[ transcribed, stored in a retrieval system, or translated into any ]
[ human or computer language, in any form or by any means; electronic, ]
[ mechanical, magnetic, optical, chemical, manual or otherwise, ]
[ without the expressed written permission of the author. ]
[ ]
[ The information contained in this text is believed to be correct. ]
[ The text is subject to change without notice and does not represent ]
[ a commitment on the part of the author. ]
[ The author does not make a warranty of any kind with regard to this ]
[ material, including, but not limited to, the implied warranties of ]
[ merchantability and fitness for a particular purpose. The author ]
[ shall not be liable for errors contained herein or for incidental or ]
[ consequential damages in connection with the furnishing, performance ]
[ or use of this material. ]